﻿using UnityEngine;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
using System;
using System.Text;
using Chat.Common;
public enum ServerState
{
    Unstarted,Started,Stopped,WaitRcving
}

public class TcpServer
{
    public string Host { get; set; }
    public int Port { get; set;}

    private TcpListener server;
    private Task listenTask;

    public event Action<string> OnClientEnter,OnClientExit;

    ManualResetEvent mre;
    CancellationTokenSource cts;
    
    // 接收到的数据格式:HEAD|TYPE|CMD|TAIL

    public TcpServer()
    {
        CurrentState = ServerState.Unstarted;   // 默认状态
        Host = "127.0.0.1";     // 默认监听地址
        Port = 12345;       //默认监听端口
    }
    /// <summary>
    /// 启动聊天服务器
    /// </summary>
    public void Start()
    {
        if(CurrentState == ServerState.Unstarted)
        {
            try
            {
                server = new TcpListener(IPAddress.Parse(Host), Port);
            }
            catch (Exception)
            {
                Debug.Log("服务器监听失败!");
                return;
            }          
            server.Start(); // 启动服务器
            CurrentState = ServerState.Started;
            mre = new ManualResetEvent(true);
            cts = new CancellationTokenSource();
            listenTask = new Task(() => { Listen(cts.Token); });         
            listenTask.Start(); // 启动监听任务
        }
    }
    /// <summary>
    /// 暂停聊天服务器
    /// </summary>
    public void Pause()
    {
        if (CurrentState == ServerState.WaitRcving)
        {
            mre.Reset();
            CurrentState = ServerState.Stopped;
        }
    }
    /// <summary>
    /// 恢复聊天服务器运行
    /// </summary>
    public void Resume()
    {
        if(CurrentState == ServerState.Stopped)
        {
            mre.Set();
            CurrentState = ServerState.WaitRcving;
        }
    }
    /// <summary>
    /// 销毁聊天服务器
    /// </summary>
    public void Destory()
    {
        if(CurrentState != ServerState.Unstarted)
        {
            server.Stop();
            mre.Dispose();
            cts.Cancel();
            cts.Dispose();
            CurrentState = ServerState.Unstarted;
        }
    }
    /// <summary>
    /// 聊天服务器监听方法
    /// </summary>
    /// <param name="token"></param>
    private void Listen(CancellationToken token)
    {
        while (true)
        {
            if (token.IsCancellationRequested)
                return;
            mre.WaitOne();
            CurrentState = ServerState.WaitRcving;
            if (!server.Pending()) // 此次没有客户等待进入
                continue;
            string clientId = Guid.NewGuid().ToString("N"); // 为新用户分配一个GUID
            Singleton<ClientManager>.GetInstance().Add(new BaseClient() {
                Id = clientId,
                Name = clientId,
                TcpClient = server.AcceptTcpClient(),
            });
            Task clientEnterTask = new Task(() => {  // 定义异步客户进入方法
                OnClientEnterAsync(clientId);
            });
            clientEnterTask.Start(); // 执行异步客户进入        
        }
    }
    /// <summary>
    /// 客户进入回调方法
    /// </summary>
    /// <param name="clientId">进入客户的ID</param>
    /// <param name="client">进入客户的TcpClient</param>
    private void OnClientEnterAsync(string clientId)
    {
        OnClientEnter(clientId);
        Task asyncTask = new Task(() => {   // 定义异步数据接收方法
            OnDataReceivedAsync(clientId);
        });
        asyncTask.Start();  //执行异步数据接收

    }
    /// <summary>
    /// 客户退出回调方法
    /// </summary>
    /// <param name="clientId">退出客户的Id</param>
    /// <param name="client">退出客户的TcpClient</param>
    private void OnClientExitAsync(string clientId)
    {
        OnClientExit(clientId);
    }
    /// <summary>
    /// 异步数据接收方法
    /// </summary>
    /// <param name="clientId">传递数据的客户ID</param>
    /// <param name="client">传递数据的客户Client</param>
    /// <param name="stream">传递的数据流</param>
    private void OnDataReceivedAsync(string clientId)
    {
        byte[] data = new byte[Common.maxBufferSize];
        int i=0;
        bool isClosed = false;
        TcpClient client = Singleton<ClientManager>.GetInstance().GetValue(clientId).TcpClient;
        NetworkStream stream = client.GetStream();
        while (true)
        {          
            do
            {
                if (client == null || !client.Connected || stream == null || !stream.CanRead)
                    break;
                i = stream.Read(data, 0, data.Length);
                if (i == 0)
                {
                    isClosed = true;
                    break;
                }
                byte[] msg = new byte[i];
                Array.Copy(data, msg, i);
                Task asyncTask = new Task(() => { HandleData(clientId,msg); });
                asyncTask.Start();
                mre.WaitOne();

            } while (stream.DataAvailable);
            if (isClosed)
                break;
        }
        //  断开连接
        {
            stream.Close();
            OnClientExitAsync(clientId);
        }
    }
    /// <summary>
    /// 服务器收到数据的处理方法
    /// </summary>
    /// <param name="data">收到的数据</param>
    private void HandleData(string clientId,byte[] data)
    {
        // 数据格式:命令头|命令类型|命令|命令尾
        int cmdHeadSize = Common.cmdHeadSize;
        int cmdTailSize = Common.cmdTailSize;
        int cmdTypeSize = Common.cmdTypeSize;
        string rcvDataHead = Common.rcvDataHead;
        string rcvDataTail = Common.rcvDataTail;
        int dataLength = data.Length; // 收到的数据长度
        int minDataSize = cmdHeadSize + cmdTailSize + cmdTypeSize; //有效数据最小长度
        if (dataLength >= minDataSize)
        {
            int cmdSize = dataLength - minDataSize; // 有效命令长度
            byte[] commandHead = new byte[cmdHeadSize];
            byte[] commandTail = new byte[cmdTailSize];
            byte[] commandType = new byte[cmdTypeSize];
            byte[] command = new byte[cmdSize];
            Array.Copy(data, 0, commandHead, 0, cmdHeadSize); // 取出命令头
            Array.Copy(data, cmdHeadSize, commandType, 0, cmdTypeSize); // 取出命令类型
            Array.Copy(data, cmdHeadSize + cmdTypeSize, command, 0, cmdSize); // 取出命令
            Array.Copy(data, dataLength - cmdTailSize, commandTail, 0, cmdTailSize); //命令尾
            // 命令类型转换
            string strCmdHead = Encoding.UTF8.GetString(commandHead);
            string strCmdTail = Encoding.UTF8.GetString(commandTail);
            string strCmdType = Encoding.UTF8.GetString(commandType);
            string strCmd = Encoding.UTF8.GetString(command);
            // 判断数据是否完整
            if (string.Compare(strCmdHead.Trim(),rcvDataHead,true) == 0 && string.Compare(strCmdTail.Trim(),rcvDataTail,true) == 0)
            {
                IHandleable handle = RcvMsgHandleFactory.Create(strCmdType.Trim());
                Task asyncTask = new Task(() => { handle.Handle(clientId,strCmd); });
                asyncTask.Start();
            }
            else
                Debug.Log("Received data but no intact……"); // 不完整数据
                
        }
        else
            Debug.Log("Received data but no available……"); // 无效数据
            
    }
    /// <summary>
    /// 服务器当前状态
    /// </summary>
    public ServerState CurrentState { get; private set; }
}
